package com.hust.hui.quicksilver.alarm;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.hust.hui.quicksilver.alarm.entity.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * Created by yihui on 2017/4/28.
 */
public class ConfigWrapper {
    private static final String DEFAULT_ALARM_KEY = "default";

    private static final BasicAlarmConfig DEFAULT_ALARM_CONFIG = getDefaultAlarmConfig();

    private static final Logger logger = LoggerFactory.getLogger(ConfigWrapper.class);

    private static final TypeReference<Map<String, BasicAlarmConfig>> typeReference = new TypeReference<Map<String, BasicAlarmConfig>>() {
    };


    private ConcurrentHashMap<String, AlarmConfig> configMap;


    private long lastConfigModifyTime;


    public ConfigWrapper(String fileName) {
        configMap = new ConcurrentHashMap<>();

        File file = new File(fileName);
        String configs = getConfigsFromFile(file);


        // 每分钟判断下文件是否有更新
        ScheduledExecutorService scheduleExecutorService = Executors.newScheduledThreadPool(1);
        scheduleExecutorService.scheduleAtFixedRate(() -> {
            if (file.lastModified() > lastConfigModifyTime) {
                initConfig(getConfigsFromFile(file));
            }
        }, 0, 1, TimeUnit.MINUTES);


        // 加载报警配置项到内存
        initConfig(configs);
    }


    private String getConfigsFromFile(File file) {
        // 从本地文件中获取配置信息, 并监听配置文件的变更事件
        String configs = "";
        try {
            lastConfigModifyTime = file.lastModified();
            BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
            configs = br.readLine();
            br.close();
        } catch (IOException e) {
            logger.error("read config error! path:{}, e:{}", file.getName(), e);
        }

        return configs;
    }


    /**
     * 初始化配置信息
     *
     * @param configs
     */
    private void initConfig(String configs) {
        Map<String, BasicAlarmConfig> map = parseStrConfig2Map(configs);


        // 尽量避免多线程获取配置参数时,出现并发修改的异常, 这里采用全覆盖方式
        ConcurrentHashMap<String, AlarmConfig> backConfigMap = new ConcurrentHashMap<>();
        AlarmConfig temp;
        for (Map.Entry<String, BasicAlarmConfig> entry : map.entrySet()) {
            temp = parseConfig(entry.getValue());
            if (temp == null) {
                continue;
            }


            // 支持多个报警类型（以英文逗号进行分割） 对应同一个报警配置
            for (String key : StringUtils.split(entry.getKey(), ",")) {
                backConfigMap.put(key, temp);
            }
        }


        this.configMap = backConfigMap;
    }


    private Map<String, BasicAlarmConfig> parseStrConfig2Map(String configs) {
        Map<String, BasicAlarmConfig> map = null;
        try {
            map = JSON.parseObject(configs, typeReference);
        } catch (Exception e) {
            logger.error("ConfigWrapper.parseStrConfig2Map() init config error!");
        }

        if (map == null) {
            map = new HashMap<>(1);
        }


        if (!map.containsKey(DEFAULT_ALARM_KEY)) {
            map.put(DEFAULT_ALARM_KEY, DEFAULT_ALARM_CONFIG);
        }
        return map;
    }


    /**
     * 将配置项转换为业务DO对象, 会做一些兼容, 保证 alarmLevel. minLimit, maxLimit, users, thresholds 都不会为null
     *
     * @param basicAlarmConfig
     * @return
     */
    private AlarmConfig parseConfig(BasicAlarmConfig basicAlarmConfig) {
        if (basicAlarmConfig.getUsers() == null || basicAlarmConfig.getUsers().isEmpty()) { // 如果没有填写用户, 则直接抛弃
            return null;
        }

        AlarmConfig alarmConfig = new AlarmConfig();

        // 如果配置的报警类型是异常的, 则下面会兼容一把，设置为 NONE, 避免因为配置的原因导致系统异常
        alarmConfig.setAlarmLevel(AlarmLevelEnum.getAlarm(basicAlarmConfig.getAlarmLevel()));
        alarmConfig.setAutoIncEmergency(basicAlarmConfig.isAutoIncEmergency());
        // 报警用户, 要求用户必须存在
        alarmConfig.setUsers(StringUtils.join(basicAlarmConfig.getUsers(), ","));
        // 报警上限, 如果用户没有填写，采用默认的（因为短信报警按条数要钱, 没必要一直无上限的报）
        alarmConfig.setMaxLimit(basicAlarmConfig.getMaxLimit() == null ? AlarmConfig.DEFAULT_MAX_NUM : basicAlarmConfig.getMaxLimit());
        // 报警下限, 如果用户没有填写, 采用默认的最小值0
        alarmConfig.setMinLimit(basicAlarmConfig.getMinLimit() == null ? AlarmConfig.DEFAULT_MIN_NUM : basicAlarmConfig.getMinLimit());


        List<AlarmThreshold> alarmThresholdList = new ArrayList<>(basicAlarmConfig.getThreshold().size());
        for (BasicAlarmThreshold basicAlarmThreshold: basicAlarmConfig.getThreshold()) {
            AlarmThreshold temp = new AlarmThreshold();
            temp.setAlarmLevel(AlarmLevelEnum.getAlarm(basicAlarmThreshold.getType()));
            temp.setThreshold(basicAlarmThreshold.getThreshold());
            temp.setUsers(StringUtils.join(basicAlarmThreshold.getUsers(), ","));

            alarmThresholdList.add(temp);
        }


        Collections.sort(alarmThresholdList);
        alarmConfig.setAlarmThreshold(alarmThresholdList);
        return alarmConfig;
    }


    /**
     * 一个保底的报警方案
     *
     * @return
     */
    private static BasicAlarmConfig getDefaultAlarmConfig() {
        BasicAlarmConfig defaultConfig = new BasicAlarmConfig();
        defaultConfig.setMinLimit(5);
        defaultConfig.setMaxLimit(30);
        defaultConfig.setUsers(Collections.singletonList("yihui"));
        defaultConfig.setAlarmLevel(AlarmLevelEnum.NONE.name());
        defaultConfig.setAutoIncEmergency(true);

        BasicAlarmThreshold defaultWeiXinThreshold = new BasicAlarmThreshold();
        defaultWeiXinThreshold.setThreshold(10);
        defaultWeiXinThreshold.setType(AlarmLevelEnum.WEIXIN.name());
        defaultWeiXinThreshold.setUsers(Collections.singletonList("yihui"));

        BasicAlarmThreshold defaultSmsThreshold = new BasicAlarmThreshold();
        defaultSmsThreshold.setType(AlarmLevelEnum.SMS.name());
        defaultSmsThreshold.setThreshold(20);
        defaultSmsThreshold.setUsers(Collections.singletonList("132132132132"));

        defaultConfig.setThreshold(Arrays.asList(defaultSmsThreshold, defaultWeiXinThreshold));

        return defaultConfig;
    }


    /**
     * 获取异常类型对应的报警配置项, 若不存在则返回默认的配置项
     * @param key
     * @return
     */
    public AlarmConfig getConfig(String key) {
        if (configMap.containsKey(key)) {
            return configMap.get(key);
        } else {
            return configMap.get(DEFAULT_ALARM_KEY);
        }
    }


    /**
     * 判断是否允许报警
     *
     * @param enableKey
     * @return
     */
    public boolean alarmEnable(String enableKey) {
//        从配置文件中获取开关
        return true;
    }
}
